<!DOCTYPE html>

<html lang="en">
  <head>
    
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <title>Dependency Injection Explained &mdash; Phalcon 3.0.1 文档</title>
    <meta name="keywords" content="php, phalcon, phalcon php, php framework, faster php framework">
    <link rel="stylesheet" type="text/css" href="http://cdn.staticfile.org/twitter-bootstrap/3.3.6/css/bootstrap.min.css" />
    <link rel="stylesheet" type="text/css" href="/www/css/phalcon.min.css" />
    <link href='//fonts.googleapis.com/css?family=Open+Sans:700,400' rel='stylesheet' type='text/css'>
    <link href="//fonts.googleapis.com/css?family=Merriweather:400,700" rel="stylesheet" type="text/css" />
    <!--
    EUROPE <link href='//fonts.googleapis.com/css?family=Open+Sans:700,400&subset=latin-ext' rel='stylesheet' type='text/css'>
    GREEK <link href='//fonts.googleapis.com/css?family=Open+Sans:700,400&subset=greek-ext' rel='stylesheet' type='text/css'>
    RUSSIA <link href='//fonts.googleapis.com/css?family=Open+Sans:700,400&subset=cyrillic-ext,latin' rel='stylesheet' type='text/css'>
    -->

    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->

    <link rel="stylesheet" href="../static/pygments.css" type="text/css" />
    <link rel="stylesheet" href="../static/docs.css" type="text/css" />
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '../',
        VERSION:     '3.0.1',
        COLLAPSE_MODINDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>

    <script src="http://cdn.staticfile.org/jquery/1.8.1/jquery.min.js"></script>
    <script type="text/javascript" src="../static/docs.js"></script>
    <link rel="shortcut icon" href="../static/favicon.ico"/>
    <link rel="top" title="Phalcon 3.0.1 文档" href="../index.html" />
    <link rel="next" title="Understanding How Phalcon Applications Work" href="applications-explained.html" />
    <link rel="prev" title="提高性能：下一步该做什么？（Increasing Performance: What’s next?）" href="whats-next.html" /> 
  </head>
  <body>

<header class="page-header">
    <nav class="navbar" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#main-menu-container">
                    <span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span>
                </button>
                <a class="navbar-brand phalcon-logo" href="/"><span itemprop="name" class="sr-only">Phalcon PHP</span></a>
            </div>

            <div class="collapse navbar-collapse navbar-right" id="main-menu-container">
                <ul class="nav navbar-nav main-menu">
                  <li class="first"><a href="//phalconphp.com/en/download" class="header-nav-link">Download</a></li>
                  <li><a href="//docs.phalconphp.com/en/latest/index.html" class="header-nav-link" target="_blank">Documentation</a></li>
                  <li><a href="//forum.phalconphp.com/" class="header-nav-link" target="_blank">Forum</a></li>
                  <li><a href="//blog.phalconphp.com/" class="header-nav-link" target="_blank">Blog</a></li>
                  <li><a href="//phalconist.com/" class="header-nav-link" target="_blank">Resources</a></li>
                  <li><a href="//phalconphp.com/en/about">About</a></li>
                  <li><div align="right">
                      <iframe src="https://ghbtns.com/github-btn.html?user=phalcon&amp;repo=cphalcon&amp;type=watch&amp;count=true&amp;size=large"
      allowtransparency="true" frameborder="0" scrolling="0" width="152px" height="30px"></iframe>
                    </div></li>
                </ul>
            </div>
        </div>
    </nav>
  </header>

<div class="heading">
    <div class="container">
        <div class="row">
            <h2>Documentation</h2>
        </div>
    </div>
</div>
    <div class="related">
      <ul>
        <li class="right" >
          <a href="../genindex.html" title="总目录"
             accesskey="I">索引</a></li>
        <li class="right" >
          <a href="applications-explained.html" title="Understanding How Phalcon Applications Work"
             accesskey="N">下一页</a> |</li>
        <li class="right" >
          <a href="whats-next.html" title="提高性能：下一步该做什么？（Increasing Performance: What’s next?）"
             accesskey="P">上一页</a> |</li>
        <li><a href="//phalconphp.com">Home</a> &raquo;</li>
        <li><a href="../index.html">Phalcon 3.0.1 文档</a> &raquo;</li> 
      </ul>
    </div>  

      <table width="100%" align="center" cellpadding="0" cellspacing="0">
        <tr>
      <td class="primary-box" width="25%" valign="top">
            <div>
            <div id="searchbox" style="">
                <!--<form class="search" action="http://readthedocs.org/search/project/" method="get">
                  <input type="search" name="q" size="25" placeholder="Search">
                  <input type="submit" value="Go">
                  <input type="hidden" name="selected_facets" value="project:">
                </form>-->
                <div style="width:200px;padding:10px">
                  <gcse:searchbox-only></gcse:searchbox-only>
                </div>
            </div>
            </div>
            <div style="padding:5px;padding-left:10px">
              <div id="carbonads-container">
                <div class="carbonad"><div id="azcarbon"></div>
                <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=phalconphpcom" id="_carbonads_js"></script>
                </div></div>
            </div>
            <h4>上一个主题</h4>
            <p class="topless"><a href="whats-next.html" title="上一章">&lt; 提高性能：下一步该做什么？（Increasing Performance: What&#8217;s next?）</a></p>
            <h4>下一个主题</h4>
            <p class="topless"><a href="applications-explained.html" title="下一章">Understanding How Phalcon Applications Work &gt;</a></p>
            <h3>本页</h3>
            <ul class="this-page-menu">
              <li><a href="../sources/reference/di-explained.md" rel="nofollow">显示源代码</a></li>
            </ul>
        </td>
          <td class="second-box" valign="top">
            <div class="document">
                <div class="documentwrapper">
                  <div class="bodywrapper">
                    <div class="body" >
                      
  <div class="section" id="dependency-injection-explained">
<h1>Dependency Injection Explained<a class="headerlink" href="#dependency-injection-explained" title="永久链接至标题">¶</a></h1>
<p>接下来的例子有些长，但解释了为什么我们使用依赖注入与服务定位器.
首先，假设我们正在开发一个组件，叫SomeComponent，它执行的内容现在还不重要。
我们的组件需要依赖数据库的连接。</p>
<p>在下面第一个例子中，数据库的连接是在组件内部建立的。这种方法是不实用的；事实上这样做的话，我们不能改变创建数据库连接的参数或者选择不同的数据库系统，因为连接是当组件被创建时建立的。</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>

<span class="k">class</span> <span class="nc">SomeComponent</span>
<span class="p">{</span>
    <span class="sd">/**</span>
<span class="sd">     * 连接数据库的实例是被写死在组件的内部</span>
<span class="sd">     * 因此，我们很难从外部替换或者改变它的行为</span>
<span class="sd">     */</span>
    <span class="k">public</span> <span class="k">function</span> <span class="nf">someDbTask</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nv">$connection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Connection</span><span class="p">(</span>
            <span class="p">[</span>
                <span class="s2">&quot;host&quot;</span>     <span class="o">=&gt;</span> <span class="s2">&quot;localhost&quot;</span><span class="p">,</span>
                <span class="s2">&quot;username&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;root&quot;</span><span class="p">,</span>
                <span class="s2">&quot;password&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;secret&quot;</span><span class="p">,</span>
                <span class="s2">&quot;dbname&quot;</span>   <span class="o">=&gt;</span> <span class="s2">&quot;invo&quot;</span><span class="p">,</span>
            <span class="p">]</span>
        <span class="p">);</span>

        <span class="c1">// ...</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nv">$some</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SomeComponent</span><span class="p">();</span>

<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">someDbTask</span><span class="p">();</span>
</pre></div>
</div>
<p>为了解决这样的情况，我们建立一个setter，在使用前注入独立外部依赖。现在，看起来似乎是一个不错的解决办法：</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>

<span class="k">class</span> <span class="nc">SomeComponent</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="nv">$_connection</span><span class="p">;</span>

    <span class="sd">/**</span>
<span class="sd">     * 设置外部传入的数据库的连接实例</span>
<span class="sd">     */</span>
    <span class="k">public</span> <span class="k">function</span> <span class="nf">setConnection</span><span class="p">(</span><span class="nv">$connection</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_connection</span> <span class="o">=</span> <span class="nv">$connection</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">function</span> <span class="nf">someDbTask</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nv">$connection</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_connection</span><span class="p">;</span>

        <span class="c1">// ...</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nv">$some</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SomeComponent</span><span class="p">();</span>

<span class="c1">// 建立数据库连接实例</span>
<span class="nv">$connection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Connection</span><span class="p">(</span>
    <span class="p">[</span>
        <span class="s2">&quot;host&quot;</span>     <span class="o">=&gt;</span> <span class="s2">&quot;localhost&quot;</span><span class="p">,</span>
        <span class="s2">&quot;username&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;root&quot;</span><span class="p">,</span>
        <span class="s2">&quot;password&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;secret&quot;</span><span class="p">,</span>
        <span class="s2">&quot;dbname&quot;</span>   <span class="o">=&gt;</span> <span class="s2">&quot;invo&quot;</span><span class="p">,</span>
    <span class="p">]</span>
<span class="p">);</span>

<span class="c1">// 向组件注入数据连接实例</span>
<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">setConnection</span><span class="p">(</span><span class="nv">$connection</span><span class="p">);</span>

<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">someDbTask</span><span class="p">();</span>
</pre></div>
</div>
<p>想一下，假设我们使用这个组件在应用内的好几个地方都用到，然而我们在注入连接实例时还需要建立好几次数据的连接实例。
如果我们可以获取到数据库的连接实例而不用每次都要创建新的连接实例，使用某种全局注册表可以解决这样的问题：</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>

<span class="k">class</span> <span class="nc">Registry</span>
<span class="p">{</span>
    <span class="sd">/**</span>
<span class="sd">     * 返回数据库连接实例</span>
<span class="sd">     */</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">getConnection</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nx">Connection</span><span class="p">(</span>
            <span class="p">[</span>
                <span class="s2">&quot;host&quot;</span>     <span class="o">=&gt;</span> <span class="s2">&quot;localhost&quot;</span><span class="p">,</span>
                <span class="s2">&quot;username&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;root&quot;</span><span class="p">,</span>
                <span class="s2">&quot;password&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;secret&quot;</span><span class="p">,</span>
                <span class="s2">&quot;dbname&quot;</span>   <span class="o">=&gt;</span> <span class="s2">&quot;invo&quot;</span><span class="p">,</span>
            <span class="p">]</span>
        <span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">class</span> <span class="nc">SomeComponent</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="nv">$_connection</span><span class="p">;</span>

    <span class="sd">/**</span>
<span class="sd">     * 设置外部传入的数据库的连接实例</span>
<span class="sd">     */</span>
    <span class="k">public</span> <span class="k">function</span> <span class="nf">setConnection</span><span class="p">(</span><span class="nv">$connection</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_connection</span> <span class="o">=</span> <span class="nv">$connection</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">function</span> <span class="nf">someDbTask</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nv">$connection</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_connection</span><span class="p">;</span>

        <span class="c1">// ...</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nv">$some</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SomeComponent</span><span class="p">();</span>

<span class="c1">// 把注册表中的连接实例传递给组件</span>
<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">setConnection</span><span class="p">(</span><span class="nx">Registry</span><span class="o">::</span><span class="na">getConnection</span><span class="p">());</span>

<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">someDbTask</span><span class="p">();</span>
</pre></div>
</div>
<p>现在，让我们设想一下，我们必须实现2个方法，第一个方法是总是创建一个新的连接，第二方法是总是使用一个共享连接：</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>

<span class="k">class</span> <span class="nc">Registry</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="k">static</span> <span class="nv">$_connection</span><span class="p">;</span>

    <span class="sd">/**</span>
<span class="sd">     * 建立一个新的连接实例</span>
<span class="sd">     */</span>
    <span class="k">protected</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">_createConnection</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nx">Connection</span><span class="p">(</span>
            <span class="p">[</span>
                <span class="s2">&quot;host&quot;</span>     <span class="o">=&gt;</span> <span class="s2">&quot;localhost&quot;</span><span class="p">,</span>
                <span class="s2">&quot;username&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;root&quot;</span><span class="p">,</span>
                <span class="s2">&quot;password&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;secret&quot;</span><span class="p">,</span>
                <span class="s2">&quot;dbname&quot;</span>   <span class="o">=&gt;</span> <span class="s2">&quot;invo&quot;</span><span class="p">,</span>
            <span class="p">]</span>
        <span class="p">);</span>
    <span class="p">}</span>

    <span class="sd">/**</span>
<span class="sd">     * 只建立一个连接实例，后面的请求只返回该连接实例</span>
<span class="sd">     */</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">getSharedConnection</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">self</span><span class="o">::</span><span class="nv">$_connection</span> <span class="o">===</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">self</span><span class="o">::</span><span class="nv">$_connection</span> <span class="o">=</span> <span class="nx">self</span><span class="o">::</span><span class="na">_createConnection</span><span class="p">();</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="nv">$_connection</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="sd">/**</span>
<span class="sd">     * 总是返回一个新的连接实例</span>
<span class="sd">     */</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">getNewConnection</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nx">self</span><span class="o">::</span><span class="na">_createConnection</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">class</span> <span class="nc">SomeComponent</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="nv">$_connection</span><span class="p">;</span>

    <span class="sd">/**</span>
<span class="sd">     * 设置外部传入的数据库的连接实例</span>
<span class="sd">     */</span>
    <span class="k">public</span> <span class="k">function</span> <span class="nf">setConnection</span><span class="p">(</span><span class="nv">$connection</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_connection</span> <span class="o">=</span> <span class="nv">$connection</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="sd">/**</span>
<span class="sd">     * 这个方法总是需要共享连接实例</span>
<span class="sd">     */</span>
    <span class="k">public</span> <span class="k">function</span> <span class="nf">someDbTask</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nv">$connection</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_connection</span><span class="p">;</span>

        <span class="c1">// ...</span>
    <span class="p">}</span>

    <span class="sd">/**</span>
<span class="sd">     * 这个方法总是需要新的连接实例</span>
<span class="sd">     */</span>
    <span class="k">public</span> <span class="k">function</span> <span class="nf">someOtherDbTask</span><span class="p">(</span><span class="nv">$connection</span><span class="p">)</span>
    <span class="p">{</span>

    <span class="p">}</span>
<span class="p">}</span>

<span class="nv">$some</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SomeComponent</span><span class="p">();</span>

<span class="c1">// 注入共享连接实例</span>
<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">setConnection</span><span class="p">(</span>
    <span class="nx">Registry</span><span class="o">::</span><span class="na">getSharedConnection</span><span class="p">()</span>
<span class="p">);</span>

<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">someDbTask</span><span class="p">();</span>

<span class="c1">// 这里我们总是传递一个新的连接实例</span>
<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">someOtherDbTask</span><span class="p">(</span>
    <span class="nx">Registry</span><span class="o">::</span><span class="na">getNewConnection</span><span class="p">()</span>
<span class="p">);</span>
</pre></div>
</div>
<p>到目前为止，我们已经看到依赖注入怎么解决我们的问题了。把依赖作为参数来传递，而不是建立在内部建立它们，这使我们的应用更加容易维护和更加解耦。不管怎么样，长期来说，这种形式的依赖注入有一些缺点。</p>
<p>例如，如果这个组件有很多依赖，
我们需要创建多个参数的setter方法​​来传递依赖关系，或者建立一个多个参数的构造函数来传递它们，另外在使用组件前还要每次都创建依赖，这让我们的代码像这样不易维护：</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>

<span class="c1">// 创建依赖实例或从注册表中查找</span>
<span class="nv">$connection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Connection</span><span class="p">();</span>
<span class="nv">$session</span>    <span class="o">=</span> <span class="k">new</span> <span class="nx">Session</span><span class="p">();</span>
<span class="nv">$fileSystem</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">FileSystem</span><span class="p">();</span>
<span class="nv">$filter</span>     <span class="o">=</span> <span class="k">new</span> <span class="nx">Filter</span><span class="p">();</span>
<span class="nv">$selector</span>   <span class="o">=</span> <span class="k">new</span> <span class="nx">Selector</span><span class="p">();</span>

<span class="c1">// 把实例作为参数传递给构造函数</span>
<span class="nv">$some</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SomeComponent</span><span class="p">(</span><span class="nv">$connection</span><span class="p">,</span> <span class="nv">$session</span><span class="p">,</span> <span class="nv">$fileSystem</span><span class="p">,</span> <span class="nv">$filter</span><span class="p">,</span> <span class="nv">$selector</span><span class="p">);</span>

<span class="c1">// ... 或者使用setter</span>
<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">setConnection</span><span class="p">(</span><span class="nv">$connection</span><span class="p">);</span>
<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">setSession</span><span class="p">(</span><span class="nv">$session</span><span class="p">);</span>
<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">setFileSystem</span><span class="p">(</span><span class="nv">$fileSystem</span><span class="p">);</span>
<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">setFilter</span><span class="p">(</span><span class="nv">$filter</span><span class="p">);</span>
<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">setSelector</span><span class="p">(</span><span class="nv">$selector</span><span class="p">);</span>
</pre></div>
</div>
<p>假设我们必须在应用的不同地方使用和创建这些对象。如果当你永远不需要任何依赖实例时，你需要去删掉构造函数的参数，或者去删掉注入的setter。为了解决这样的问题，我们再次回到全局注册表创建组件。不管怎么样，在创建对象之前，它增加了一个新的抽象层：</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>

<span class="k">class</span> <span class="nc">SomeComponent</span>
<span class="p">{</span>
    <span class="c1">// ...</span>

    <span class="sd">/**</span>
<span class="sd">     * Define a factory method to create SomeComponent instances injecting its dependencies</span>
<span class="sd">     */</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">factory</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nv">$connection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Connection</span><span class="p">();</span>
        <span class="nv">$session</span>    <span class="o">=</span> <span class="k">new</span> <span class="nx">Session</span><span class="p">();</span>
        <span class="nv">$fileSystem</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">FileSystem</span><span class="p">();</span>
        <span class="nv">$filter</span>     <span class="o">=</span> <span class="k">new</span> <span class="nx">Filter</span><span class="p">();</span>
        <span class="nv">$selector</span>   <span class="o">=</span> <span class="k">new</span> <span class="nx">Selector</span><span class="p">();</span>

        <span class="k">return</span> <span class="k">new</span> <span class="nx">self</span><span class="p">(</span><span class="nv">$connection</span><span class="p">,</span> <span class="nv">$session</span><span class="p">,</span> <span class="nv">$fileSystem</span><span class="p">,</span> <span class="nv">$filter</span><span class="p">,</span> <span class="nv">$selector</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>瞬间，我们又回到刚刚开始的问题了，我们再次创建依赖实例在组件内部！我们可以继续前进，找出一个每次能奏效的方法去解决这个问题。但似乎一次又一次，我们又回到了不实用的例子中。</p>
<p>一个实用和优雅的解决方法，是为依赖实例提供一个容器。这个容器担任全局的注册表，就像我们刚才看到的那样。使用依赖实例的容器作为一个桥梁来获取依赖实例，使我们能够降低我们的组件的复杂性：</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>

<span class="k">use</span> <span class="nx">Phalcon\Di</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Phalcon\DiInterface</span><span class="p">;</span>

<span class="k">class</span> <span class="nc">SomeComponent</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="nv">$_di</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">function</span> <span class="nf">__construct</span><span class="p">(</span><span class="nx">DiInterface</span> <span class="nv">$di</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_di</span> <span class="o">=</span> <span class="nv">$di</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">function</span> <span class="nf">someDbTask</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// 获得数据库连接实例</span>
        <span class="c1">// 总是返回一个新的连接</span>
        <span class="nv">$connection</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_di</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="s2">&quot;db&quot;</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">function</span> <span class="nf">someOtherDbTask</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// 获得共享连接实例</span>
        <span class="c1">// 每次请求都返回相同的连接实例</span>
        <span class="nv">$connection</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_di</span><span class="o">-&gt;</span><span class="na">getShared</span><span class="p">(</span><span class="s2">&quot;db&quot;</span><span class="p">);</span>

        <span class="c1">// 这个方法也需要一个输入过滤的依赖服务</span>
        <span class="nv">$filter</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">_di</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="s2">&quot;filter&quot;</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nv">$di</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Di</span><span class="p">();</span>

<span class="c1">// 在容器中注册一个db服务</span>
<span class="nv">$di</span><span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span>
    <span class="s2">&quot;db&quot;</span><span class="p">,</span>
    <span class="k">function</span> <span class="p">()</span> <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nx">Connection</span><span class="p">(</span>
            <span class="p">[</span>
                <span class="s2">&quot;host&quot;</span>     <span class="o">=&gt;</span> <span class="s2">&quot;localhost&quot;</span><span class="p">,</span>
                <span class="s2">&quot;username&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;root&quot;</span><span class="p">,</span>
                <span class="s2">&quot;password&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;secret&quot;</span><span class="p">,</span>
                <span class="s2">&quot;dbname&quot;</span>   <span class="o">=&gt;</span> <span class="s2">&quot;invo&quot;</span><span class="p">,</span>
            <span class="p">]</span>
        <span class="p">);</span>
    <span class="p">}</span>
<span class="p">);</span>

<span class="c1">// 在容器中注册一个filter服务</span>
<span class="nv">$di</span><span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span>
    <span class="s2">&quot;filter&quot;</span><span class="p">,</span>
    <span class="k">function</span> <span class="p">()</span> <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nx">Filter</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">);</span>

<span class="c1">// 在容器中注册一个session服务</span>
<span class="nv">$di</span><span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span>
    <span class="s2">&quot;session&quot;</span><span class="p">,</span>
    <span class="k">function</span> <span class="p">()</span> <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nx">Session</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">);</span>

<span class="c1">// 把传递服务的容器作为唯一参数传递给组件</span>
<span class="nv">$some</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SomeComponent</span><span class="p">(</span><span class="nv">$di</span><span class="p">);</span>

<span class="nv">$some</span><span class="o">-&gt;</span><span class="na">someDbTask</span><span class="p">();</span>
</pre></div>
</div>
<p>这个组件现在可以很简单的获取到它所需要的服务，服务采用延迟加载的方式，只有在需要使用的时候才初始化，这也节省了服务器资源。这个组件现在是高度解耦。例如，我们可以替换掉创建连接的方式，它们的行为或它们的任何其他方面，也不会影响该组件。</p>
</div>


                    </div>
                  </div>
                </div>
            </div>
          </td>
        </tr>
      </table>
    <div class="related">
      <ul>
        <li class="right" >
          <a href="../genindex.html" title="总目录"
             >索引</a></li>
        <li class="right" >
          <a href="applications-explained.html" title="Understanding How Phalcon Applications Work"
             >下一页</a> |</li>
        <li class="right" >
          <a href="whats-next.html" title="提高性能：下一步该做什么？（Increasing Performance: What’s next?）"
             >上一页</a> |</li> 
      </ul>
    </div>

      <div class="prefooter">
  <div class="container">
      <div class="row">
          <div class="col-sm-3 text-right">
              <span>Follow along:</span>
          </div>
          <div class="col-sm-6 text-center">
              <a href="https://twitter.com/phalconphp" alt="Twitter" class="btn-social btn-social-twitter"><i class="icon-twitter"></i></a>
              <a href="https://www.facebook.com/pages/Phalcon-Framework/134230726685897" alt="Facebook" class="btn-social btn-social-facebook"><i class="icon-facebook"></i></a>
              <a href="https://plus.google.com/102376109340560896457" alt="Google+" class="btn-social btn-social-googleplus"><i class="icon-googleplus"></i></a>
              <a href="https://github.com/phalcon/cphalcon" alt="Github" class="btn-social btn-social-github"><i class="icon-github"></i></a>
          </div>
          <div class="col-sm-3">
          </div>
      </div>
  </div>

</div>
<footer class="footer">
    <div class="container">
        <div class="row">
            <div class="col-xs-4 col-sm-3">
                <h4>Download</h4>
                <ul>
                    <li><a href="/download">Installing Phalcon PHP</a></li>
                    <li><a href="http://docs.phalconphp.com/en/latest/index.html" class="header-nav-link" target="_blank">Documentation</a></li>
                    <li><a href="http://api.phalconphp.com">API</a></li>
                    <li><a href="http://docs.phalconphp.com/en/latest/reference/tutorial.html">Tutorial</a></li>
                    <li><a href="http://docs.phalconphp.com/en/latest/reference/tutorial.html#sample-applications">Sample Applications</a></li>
                </ul>
            </div>
            <div class="col-xs-4 col-sm-3">
                <h4>Community</h4>
                <ul>
                    <li><a href="http://forum.phalconphp.com/" class="header-nav-link" target="_blank">Forum</a></li>
                    <li><a href="https://github.com/phalcon/cphalcon">GitHub</a></li>
                    <li><a href="https://github.com/phalcon/cphalcon/issues">Issue Tracker</a></li>
                    <li><a href="http://stackoverflow.com/questions/tagged/phalcon">Stack Overflow</a></li>
                    <li><a href="/en/testimonials">Testimonials</a></li>
                    <li><a href="http://builtwith.phalconphp.com/">Built with Phalcon</a></li>
                    <li><a href="http://store.phalconphp.com/">Store</a></li>
                </ul>
            </div>
            <div class="col-xs-4 col-sm-2">
                <h4>About</h4>
                <ul>
                    <li><a class="link-black" href="http://blog.phalconphp.com/">Blog</a></li>
                    <li><a href="/en/about">About</a></li>
                    <li><a href="/en/team">Team</a></li>
                    <li><a href="/en/roadmap">Roadmap</a></li>
                    <li><a href="/en/donate">Donate</a></li>
                    <li><a href="/en/consulting">Consulting</a></li>
                    <li><a href="/en/hosting">Hosting</a></li>
                </ul>
            </div>
            <div id="license-spaccer" class="visible-xs"></div>
            <div id="license-wrapper" class="col-xs-12 col-sm-4">
                <p class="license">
                    Phalcon is an open-source PHP framework <br>built as a C-extension. It is available under the <br>
                    <a href="http://opensource.org/licenses/BSD-3-Clause" target="_blank">new BSD License</a>.
                    <br>
                    <br>
                    Except where otherwise noted, content on this site is licensed under the
                    <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 License.</a>
                </p>
            </div>
        </div>
    </div>
</footer>

    </div>
    <script type="text/javascript">
    $(window).on("load", function(){
      var cx = '009733439235723428699:lh9ltjgvdz8';
      var gcse = document.createElement('script');
      gcse.type = 'text/javascript';
      gcse.async = true;
      gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//www.google.com/cse/cse.js?cx=' + cx;
      var s = document.getElementsByTagName('script')[0];
      s.parentNode.insertBefore(gcse, s);
    });
    </script>

  </body>
</html>